#include <QFileInfo>
#include <QDir>
#include "ModuleScope.h"
#include "ast/Import.h"
#include "grammar/python3/PythonGrammar30.h"
#include "grammar/python3/PythonGrammar30TokenManager.h"


ModuleScope::ModuleScope(const QFileInfo& fileName):
    Scope(NULL, fileName)
{
    //buildScope();
}

ModuleScope::~ModuleScope()
{
    _lines.clear();
    _poses.clear();
    _text.clear();
    _names.clear();
    _childScopes.clear();
}

void ModuleScope::setAst(const ModulePtr& moduleAst)
{
    _moduleAst = moduleAst;
}

void ModuleScope::buildScope()
{
    _lines.clear();
    _poses.clear();
    _text.clear();
    _names.clear();
    _childScopes.clear();

    visitModule(_moduleAst);
    LineBuilder build(this);
    build.traverse(_moduleAst);
}

QList<SimpleNodePtr> ModuleScope::astInText(const QString& text)
{
    return _text.value(text, QList<SimpleNodePtr>());
}

QList<Error> ModuleScope::errorList()
{
    return _errorList;
}

void ModuleScope::onParseError(const QString& msg, int line, int col)
{
    Error e;
    e.code = SyntaxError;
    e.msg = msg;
    e.line = line;
    e.col = col;
    _errorList.append(e);
}

void ModuleScope::visitModule(const ModulePtr &node)
{
     node->traverse(this);
}

QList<SimpleNodePtr> ModuleScope::astInLine(int line)
{
    return _lines.value(line, QList<SimpleNodePtr>());
}

void ModuleScope::refresh(const QString& content)
{
    CharStream stream(content);
    PythonGrammar30TokenManager in(&stream);
    PythonGrammar30 grammar(&in);

    _errorList.clear();
    connect(&grammar, SIGNAL(parseError(QString, int, int)), this, SLOT(onParseError(QString, int, int)));

    ModulePtr newRoot = grammar.file_input().dynamicCast<Module>();
    setAst(newRoot);
    buildScope();
}

bool ModuleScope::shiftAst(int fromPos, int removed, int added)
{
    int spos = -1;
    foreach(int pos, _poses.keys()){
        if (fromPos >= pos){
            spos = pos;
        } else {
            break;
        }
    }
    bool ret = false;
    if (spos >= 0){
        if (_poses[spos]->startPos < fromPos && _poses[spos]->endPos >= fromPos){
            //qDebug() << _poses[spos]->toString();
            _poses[spos]->endColumn += added - removed;
            _poses[spos]->endPos += added - removed;
            //ret = _poses[spos]->type() == "Num" || _poses[spos]->type() == "Str" || _poses[spos]->type() == "Name";
        }
    }

    QMap<int, SimpleNodePtr> _newPoses;
    foreach(int pos, _poses.keys()){
        if (_poses[pos]->startPos > fromPos){
            _poses[pos]->beginColumn += added - removed;
            _poses[pos]->endColumn += added - removed;
            _poses[pos]->startPos += added - removed;
            _poses[pos]->endPos += added - removed;
        }
        _newPoses[_poses[pos]->startPos] = _poses[pos];
    }
    _poses = _newPoses;
    return ret;
}

LineBuilder::LineBuilder(ModuleScope * scope):
    VisitorBase(),
    _scope(scope)
{

}

void LineBuilder::traverse(const SimpleNodePtr& node)
{
    if (node->startPos != node->endPos)
        _scope->_poses[node->startPos] = node;

    for(int i = node->beginLine; i <= node->endLine; ++i){
        _scope->_lines[i].append(node);
    }
    //qDebug() << node->toString() << node->beginLine << node->beginColumn;
    //qDebug() << node->type() << node->startPos << node->endPos;
    node->traverse(this);
}

